package com.tanhua.app.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tanhua.api.*;
import com.tanhua.app.exception.BusinessException;
import com.tanhua.app.intercept.UserHolder;
import com.tanhua.commons.utils.Constants;
import com.tanhua.config.template.HuanXinTemplate;
import com.tanhua.model.dto.RecommendUserDto;
import com.tanhua.model.mongo.RecommendUser;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.pojo.Question;
import com.tanhua.model.pojo.UserInfo;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.NearUserVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.TodayBest;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.logging.SimpleFormatter;
import java.util.stream.Collectors;

@Service
public class TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApil;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @DubboReference
    private UserLikeApi userLikeApi;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MessageService messageService;

    @DubboReference
    private UserLocationApi userLocationApi;

    @DubboReference
    private VisitorsApi visitorsApi;

    /**
     * 查询今日佳人的信息
     * @return
     */
    public TodayBest todayBest() {
        //1.获取当前用户的id
        Long userId = UserHolder.getUserId();

        //2.调用Api接口查询
        RecommendUser recommendUser = recommendUserApi.findWithMaxScore(userId);

        //3.将RecommendUser转化为TodayBase对象
        UserInfo userInfo = userInfoApil.findById(recommendUser.getUserId());
        TodayBest todayBestVo = TodayBest.init(userInfo, recommendUser);

        //4.返回结果
        return todayBestVo;

    }


    /**
     * 分页查询推荐好友列表
     * @param recommendUserDto
     * @return
     */
    public PageResult recommendation(RecommendUserDto recommendUserDto) {
        //1、调用Api查询推荐好友列表(得到登录用户的的全部推荐好友，一个集合)
        List<RecommendUser> recommendUserList = recommendUserApi.findByUser(UserHolder.getUserId());

        //2.调用Api根据查询到的好友列表的id查询每个好友列表的详情
            //2.1判断查询的好列表集合是否为空（新用户还不存在好友推荐）
            if (CollUtil.isEmpty(recommendUserList)){
                //为空，直接返回
                return new PageResult(recommendUserDto.getPage(),recommendUserDto.getPagesize(),0,null);
            }
            //2.2获取该登录用户全部推荐好友的id
            List<Long> ids = recommendUserList.stream().map(RecommendUser::getUserId).collect(Collectors.toList());


        //3.查询推荐好友的详情  分页查询
        Page<UserInfo> pages = userInfoApil.findByIds(ids,recommendUserDto);

        //4.构造vo对象，对查询到的推荐好友和其详情封装成对象返回
            //4.1将查询到的推荐好友的集合转为map
            Map<Long, RecommendUser> map = recommendUserList.stream().collect(Collectors.toMap(RecommendUser::getUserId, Function.identity()));
            //4.2封装称Vos对象
            List<TodayBest> vos = new ArrayList<>();
            //4.3遍历推荐好友详情，将好友详情和每个好友的RecommendUser信息封装称vo对象
            for (UserInfo userInfo : pages.getRecords()) {
                //获取每个好友的RecommendUse信息
                RecommendUser recommendUser = map.get(userInfo.getId());
                TodayBest vo = TodayBest.init(userInfo, recommendUser);
                vos.add(vo);
            }

        //5.返回结果
        return new PageResult(recommendUserDto.getPage(),recommendUserDto.getPagesize(), (int) pages.getTotal(),vos);
    }

    /**
     * 根据页面展示的佳人用户id查询佳人的信息
     * @param userId
     * @return
     */
    public TodayBest findUserInfoById(Long userId) {
        //1通过查询获得该用户的详情
        UserInfo userInfo = userInfoApil.findById(userId);

        //2查询推荐好友的信息，即推荐佳人的信息(推荐好友中的某一个佳人信息需要通过自己的id，和该佳人推荐了给谁（即当前用户）)
        RecommendUser user = recommendUserApi.findRecommenderUser(userId,UserHolder.getUserId());

        //3保存访客信息
        //3.1构建访客对象
        Visitors visitors = new Visitors();
        //3.2封装数据
        visitors.setUserId(userId);//被访问人的id,也就是当前用户所查看的佳人用户
        visitors.setVisitorUserId(UserHolder.getUserId());//访问人的id，也就是当前用户
        visitors.setFrom("首页");
        visitors.setDate(System.currentTimeMillis());
        visitors.setVisitDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        visitors.setScore(user.getScore());
        //3.3保存数据
        visitorsApi.save(visitors);
        //4返回vo对象
        TodayBest bestUser = TodayBest.init(userInfo, user);
        return bestUser;
    }


    /**
     * 查看佳人 的陌生人问题
     * @param userId
     * @return
     */
    public String findUserQuestions(Long userId) {
        //1.通过API接口调用查询方法
        Question question = questionApi.findByUserId(userId);

        //2.判断佳人是是否存在陌生人问题
        return question == null ? "您喜欢java吗？":question.getTxt();
    }

    /**
     * 回复陌生人的问题
     * @param toUserId：当前用户回复给佳人,该佳人的用户的id
     * @param reply：当前用户回复的内容
     */
    public void replyQuestions(Long toUserId, String reply) {
        //1.构建消息数据
        //查询当前用户的个人信息
        UserInfo userInfo = userInfoApil.findById(UserHolder.getUserId());
        //创建集合封装消息数据
        Map map = new HashMap();
        //当前用户的id
        map.put("userId",UserHolder.getUserId());
        //当前用户的环信id
        map.put("huanxinId", Constants.HX_USER_PREFIX +UserHolder.getUserId());
        //当前用户的昵称
        map.put("nickname",userInfo.getNickname());
        //佳人的陌生人问题
        map.put("strangerQuestion",findUserQuestions(toUserId)); //调用查询佳人的陌生人问题方法，返回的就是佳人的陌生人问题的内容
        //当前用户回复的内容
        map.put("reply", reply);
        //将封装的消息转换为json
        String message = JSON.toJSONString(map);

        //2.调用即时通讯对象发送消息
        Boolean aBoolean = huanXinTemplate.sendMsg(Constants.HX_USER_PREFIX + toUserId, message);

        //3。判断消息是否发送成功
        if (!aBoolean){
            throw new BusinessException(ErrorResult.huanXinMessageError());
        }
    }

    /**
     * 查询探花卡片列表的数据
     * @return
     */
    //探花卡片中推荐的数据(默认数据)
    @Value("${tanhua.default.recommend.users}")
    private String recommendUsers;

    public List<TodayBest> queryCardsList() {
        //1.调用API查询数据列表（排除喜欢和不喜欢的用户，数量限制10）
        List<RecommendUser> recommendUserList = recommendUserApi.queryCardsList(UserHolder.getUserId(),10);

        //2.判断查询的数据是否存在，不存在构建数据
        if (CollUtil.isEmpty(recommendUserList)){
            //2.1不存在，构建新的探花数据列表
            recommendUserList = new ArrayList<>();
            //2.2获取默认的数据（用户id）
            String[] ids = recommendUsers.split(",");
            for (String id : ids) {
                //2.3创建新的推荐用户
                RecommendUser recommendUser = new RecommendUser();
                //2.4添加推荐用户的数据
                recommendUser.setUserId(Convert.toLong(id));
                recommendUser.setToUserId(UserHolder.getUserId());
                recommendUser.setScore(RandomUtil.randomDouble(60,90));
                recommendUserList.add(recommendUser);
            }
        }

        //3.通过获得的推荐用户id，查询推荐用户的详情
        //3.1通过Stream得到推荐用户的ids
        List<Long> userIds = recommendUserList.stream().map(RecommendUser::getUserId).collect(Collectors.toList());
        //3.2调用API查询用户的详情
        List<UserInfo> userInfoList = userInfoApil.findByUserId(userIds);

        //4.将查询的用户详情集合转换成map集合
        Map<Long, UserInfo> map = userInfoList.stream().collect(Collectors.toMap(UserInfo::getId, Function.identity()));

        //5.构建vo对象
        List<TodayBest> vos = new ArrayList<>();
        for (RecommendUser recommendUser : recommendUserList) {
            //自己不要推荐给自己
            if (recommendUser.getUserId().longValue() == UserHolder.getUserId().longValue()){
                continue;
            }
            UserInfo userInfo = map.get(recommendUser.getUserId());
            if (userInfo != null){
                TodayBest todayBest = TodayBest.init(userInfo, recommendUser);
                vos.add(todayBest);
            }
        }

        //6.返回结果
        return vos;
    }

    /**
     * 探花列表右滑——喜欢操作
     * @param likeUserId
     */
    public void likeUser(Long likeUserId) {
        //1.调用API保存喜欢数据，将喜欢的数据存入redis中
       Boolean save =  userLikeApi.saveOrUpdate(UserHolder.getUserId(),likeUserId, true);

        if (!save){
            //保存失败，抛出异常
            throw new BusinessException(ErrorResult.tanhuaLikeError());
        }
        //2.保存成功，存入到redis缓存中(喜欢该用户，则需要先在不喜欢的redis缓存中删除数据，在添加到喜欢的缓存中)
        //删除不喜欢缓存集合中的数据
        redisTemplate.opsForSet().remove(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        //添加到喜欢的缓存集合中
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());

        //3.判断两者是否相互喜欢
        //查询用户喜欢的用户是否喜欢该用户（在喜欢缓存中查询查询被喜欢人的喜欢列表）
        if (redisTemplate.opsForSet().isMember(Constants.USER_LIKE_KEY + likeUserId, UserHolder.getUserId().toString())){
            //被喜欢人的喜欢集合中存在对该用户的喜欢数据，则该用户和喜欢用户相互喜欢，则用户把喜欢的人添加为好友
            messageService.contacts(likeUserId);
        }
    }

    /**
     * 探花列表左滑——不喜欢操作
     * @param likeUserId
     */
    public void notLikeUser(Long likeUserId) {
        //1.调用API保存喜欢数据，将喜欢的数据存入redis中
        Boolean save = userLikeApi.saveOrUpdate(UserHolder.getUserId(),likeUserId, false);

        if (!save){
            //保存失败，抛出异常
            throw new BusinessException(ErrorResult.tanhuaNotLikeError());
        }

        //2.保存成功，存入到redis缓存中(不喜欢该用户，则需要先在喜欢的redis缓存中删除数据，在添加到不喜欢的缓存中)
        //删除喜欢缓存集合中的数据
        redisTemplate.opsForSet().remove(Constants.USER_LIKE_KEY + UserHolder.getUserId(),likeUserId.toString());
        //添加到不喜欢的缓存集合中
        redisTemplate.opsForSet().add(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());

        //3.判断两者是否相互不喜欢
        //查询不喜欢的用户是否不喜欢该用户（在不喜欢用户的缓存中查询该用户是否被喜欢）
        if (redisTemplate.opsForSet().isMember(Constants.USER_NOT_LIKE_KEY + likeUserId, UserHolder.getUserId().toString())){
            messageService.removeContacts(likeUserId);
        }
    }

    /**
     * 探花搜索附近功能
     * @param gender
     * @param distance
     * @return
     */
    public List<NearUserVo> queryNearUser(String gender, String distance) {
        //1.调用API查询附近的用户(查询当前用户的腹肌，得到附近的所有用户id)
        List<Long> userIds = userLocationApi.queryNearUser(UserHolder.getUserId(),distance);

        //2.判断查询的集合是否为空
        if (CollUtil.isEmpty(userIds)){
            return new ArrayList<>();
        }

        //3.根据附件用户的id查询附近用户的详情,带条件查询
        List<UserInfo> userInfoList = userInfoApil.findByUserIds(userIds,gender);

        //4.封装vo对象
        List<NearUserVo> nearUserVos = new ArrayList<>();
        for (UserInfo userInfo : userInfoList) {
            //在搜附近中不展示自己
            if (UserHolder.getUserId().longValue() == userInfo.getId().longValue()){
                continue;
            }
            NearUserVo nearUserVo = NearUserVo.init(userInfo);
            nearUserVos.add(nearUserVo);
        }
        return nearUserVos;
    }
}
